/*
*	Project: Aethon
*
*	File: Animator.cpp
*
*	Author: Robert Whiting
*
*	Date: 3/26/2009
*
*	Purpose: 
*/

#include "../include/Animator.h"

//#######################################################
void Animator::init(void){
	//fprintf(stderr,"Animator::init\n");
	frame firstFrame;
	totalTime=.001;
/*	firstFrame.time = .001;
	for(int i=0; i<15; i++){
		firstFrame.names.push_back("start");
		firstFrame.relativeRotations.push_back(vector3f(0,0,0));
	}*/
//	frameQueue.push(firstFrame);
	startFrame = firstFrame;
//	loadFrame();
	time = Timer::getInstanceOf();
	string filename = "../data/movements/animator.txt";
	ifstream inData;
	inData.open(filename.c_str());
	string token;
    if(!inData)
    	printf("Data file failed\n");
    inData >> token;
	while(inData){
		loadMovement(token);
		inData >> token;
	}
	inData.close();
}//end init

//#######################################################
void Animator::loadMovement(string filename){
	//fprintf(stderr,"Animator::loadMovement '%s'\n",filename.c_str());
	//pair<map< string, vector<frame> >::iterator,bool> ret;
	vector<frame> tempMovement;
	string name = filename;
	
	filename = "../data/movements/" + filename + ".mv";
	ifstream inData;
	inData.open(filename.c_str());
	string token;
	frame tempFrame;
	if(!inData){
		fprintf(stderr,"Data file failed: '%s'\n",filename.c_str());
	}
	inData >> token;
	while(inData){
		if(inData && token == "f"){
			tempFrame.load(inData);
			tempMovement.push_back(tempFrame);
		}else{
			//something is wrong
			fprintf(stderr,"error: incorrect movement file format\n");
		}
		inData >> token;
	}
	//push temp movement onto global with name
	movements.insert(pair< string, vector<frame> >(name,tempMovement) );
	//fprintf(stderr,"loadMovement: %s\tframes: %d\n",name.c_str(),tempMovement.size());
	
	//if(!ret.second){
	//	fprintf(stderr,"error: movement '%s' already defined",ret.first->first);
	//}
	
	inData.close();
}//end loadMovement

//#######################################################
void Animator::loadFrame(void){
	//fprintf(stderr,"Loading new frame\n");
	startFrame = frameQueue.front();
	frameQueue.pop();
	deltaVector.clear();
	vector3f delta;
	for(int i = 0; i < (int)startFrame.relativeRotations.size(); i++){
		if(!frameQueue.empty()){
			//target - source
			vector3f target = frameQueue.front().relativeRotations[i];
			vector3f source = startFrame.relativeRotations[i];
			delta = generateDelta(source, target);
		}else{
			delta.v[0] = 0;
			delta.v[1] = 0;
			delta.v[2] = 0;			
		}
		deltaVector.push_back(delta);
	}
	totalTime = startFrame.time;
}//end loadFrame

//#######################################################
vector3f Animator::generateDelta(vector3f source, vector3f target){
	vector3f deltaVector;
	float deltaFloat;
	//fprintf(stderr,"Source: %.2f %.2f %.2f\t\t",source.v[0],source.v[1],source.v[2]);
	//fprintf(stderr,"Target: %.2f %.2f %.2f\n",target.v[0],target.v[1],target.v[2]);
	for(int i=0; i<3; i++){
		deltaFloat = target.v[i] - source.v[i];
		if(deltaFloat > 180)
			deltaFloat = deltaFloat - 360;
		else if (deltaFloat < -180)
			deltaFloat = deltaFloat + 360;
		deltaVector.v[i] = deltaFloat;
	}
	//fprintf(stderr,"Generated Delta: %.2f %.2f %.2f\n",deltaVector.v[0],deltaVector.v[1],deltaVector.v[1]);
	return deltaVector;
}//end generateDelta

//#######################################################
frame Animator::update(void){
	frame interpolatedFrame;
	if(!frameQueue.empty()){
		vector3f newRotation;
		float currentTime = time->getTime();
		float percentComplete = (currentTime - startTime) / totalTime;
		//fprintf(stderr,"Time:\n\tcurrent %.2f\n\tstart %.2f\n\ttotal %.2f\n",currentTime,startTime,totalTime);
		//fprintf(stderr,"percentComplete: %f\nFrames in queue: %d\n",percentComplete,frameQueue.size());
		interpolatedFrame.time = percentComplete;
		//when frame is complete
		if(percentComplete >= 1){
			//fprintf(stderr,"Frame complete\n");
			if(!frameQueue.empty()){
				loadFrame();
				startTime = currentTime;
			}else{
				//do nothing if there are no frames on the queue
				//fprintf(stderr,"No frames in the queue\n");
			}
		}else{
			//fprintf(stderr,"Interpolating from delta and frame\n\tStart\t\tDelta\n");
			for(int i = 0; i < (int)startFrame.relativeRotations.size(); i++){
				interpolatedFrame.names.push_back(startFrame.names[i]);
				newRotation.v[0] = startFrame.relativeRotations[i].v[0] + percentComplete*deltaVector[i].v[0];
				newRotation.v[1] = startFrame.relativeRotations[i].v[1] + percentComplete*deltaVector[i].v[1];
				newRotation.v[2] = startFrame.relativeRotations[i].v[2] + percentComplete*deltaVector[i].v[2];
				interpolatedFrame.relativeRotations.push_back(newRotation);
				//fprintf(stderr,"\t%s\t%.2f %.2f %.2f    %.2f %.2f %.2f\n",startFrame.names[i].c_str(),
				//	startFrame.relativeRotations[i].v[0],startFrame.relativeRotations[i].v[1],startFrame.relativeRotations[i].v[2],
				//	deltaVector[i].v[0],deltaVector[i].v[1],deltaVector[i].v[2]);
			}
		}
	}else{
		//fprintf(stderr,"Object is not animated\n");
	}
	return interpolatedFrame;
}//end update


//#######################################################
void Animator::interruptMovement(string movementName){
	frame tempFrame = frameQueue.front();
	while(!frameQueue.empty()){
		frameQueue.pop();
	}
	frameQueue.push(tempFrame);
	pushMovement(movementName);
}//end interruptMovement

//#######################################################
void Animator::pushMovement(string movementName){
	vector<frame> tempMovement = movements[movementName];
	//fprintf(stderr,"pushing movements: %d\n", tempMovement.size());
	for(int i=0; i<(int)tempMovement.size(); i++){
		frameQueue.push(tempMovement[i]);
	}
}//end pushMovement


